// @Software: serve
// @File : usr_batch
// @Author : vince
// @Time : 2021/9/25 20:41
// @Description  请填写文件描述
package v1

import (
	"bytes"
	"fmt"
	"gintify/core"
	"gintify/model"
	"gintify/response"
	"gintify/util"
	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"os"
	"path"
	"strings"
	"text/template"
	"time"
)

var log = core.GetLogger()

type UsrBatch struct {
	Source   string `json:"source"`
	Template string `json:"template"`
	Project  string `json:"project"`
	FileName string `json:"filename"`
}

type IBatchController interface {
	IRestController
}
type BatchController struct {
	// 空结构体
	//e *batch.Enforcer
}

// @Summary 新增Batch规则
// @Description 在数据库中获取Batch信息
// @Tags Batch
// @Accept  json
// @Produce  json
// @Security ApiKeyAuth
// @Success 200 {object} model.SysBatch "{"code":0,"msg":"OK","body": {}}"
// @Router /api/v1/batch [post]
func (b BatchController) Post(c *gin.Context) {
	panic("implement me")
}

// @Summary 获取Batch规则
// @Description 在数据库中获取Batch信息
// @Tags Batch
// @Accept  json
// @Produce  json
// @Security ApiKeyAuth
// @Success 200 {object} []model.SysBatch "{"code":0,"msg":"OK","body": {}}"
// @Router /api/v1/batch [get]
func (b BatchController) GetList(c *gin.Context) {
	panic("implement me")
}

// @Summary 获取Batch规则
// @Description 在数据库中获取Batch信息
// @Tags Batch
// @Accept  json
// @Produce  json
// @Security ApiKeyAuth
// @Param id path uint64 true "batch_rule id in database"
// @Success 200 {object} model.SysBatch "{"code":0,"msg":"OK","body": {}}"
// @Router /api/v1/batch/{id} [get]
func (b BatchController) Get(c *gin.Context) {
	panic("implement me")
}

// @Summary 更新Batch规则
// @Description 在数据库中更新Batch信息
// @Tags Batch
// @Accept  json
// @Produce  json
// @Security ApiKeyAuth
// @Param id path uint64 true "batch_rule id in database"
// @Success 200 {object} model.SysBatch "{"code":0,"msg":"OK","body": {}}"
// @Router /api/v1/batch/{id} [put]
func (b BatchController) Put(c *gin.Context) {
	panic("implement me")
}

// @Summary 更新Batch规则
// @Description 在数据库中更新Batch信息
// @Tags Batch
// @Accept  json
// @Produce  json
// @Security ApiKeyAuth
// @Param id path uint64 true "batch_rule id in database"
// @Success 200 {object} model.SysBatch "{"code":0,"msg":"OK","body": {}}"
// @Router /api/v1/batch/{id} [patch]
func (b BatchController) Patch(c *gin.Context) {
	panic("implement me")
}

// @Summary 删除Batch规则
// @Description 在数据库中删除Batch信息
// @Tags Batch
// @Accept  json
// @Produce  json
// @Security ApiKeyAuth
// @Param id path uint64 true "batch_rule id in database"
// @Success 200 {object} model.SysBatch "{"code":0,"msg":"OK","body": {}}"
// @Router /api/v1/batch/{id} [delete]
func (b BatchController) Delete(c *gin.Context) {
	panic("implement me")
}

// @Summary 上传Excel文件
// @Description 上传Excel文件
// @Tags Batch
// @Accept  json
// @Produce  json
// @Security ApiKeyAuth
// @Success 200 {object} model.SysBatch "{"code":0,"msg":"OK","body": {}}"
// @Router /api/v1/batch [post]
func (b BatchController) UploadExcel(c *gin.Context) {
	claims, _ := c.Get("user")
	user := claims.(model.SysUser)
	// 单文件
	file, err := c.FormFile("file")
	if err != nil {
		response.Error(c, "服务器接收文件出错", err)
		return
	}
	filename := strings.TrimSuffix(file.Filename, path.Ext(file.Filename))
	dir := fmt.Sprintf("./upload/%s/%s", user.Name, filename)
	if err := util.CreateDir(dir); err != nil {
		response.Error(c, "Create DIR faild", err)
		return
	}
	dst := fmt.Sprintf("%s/%s", dir, file.Filename)
	// 上传文件至指定目录
	if err := c.SaveUploadedFile(file, dst); err != nil {
		response.Error(c, "服务器处理文件出错", err)
		return
	}

	//header, err := ReadHeader(dst)
	//if err != nil {
	//	response.Error(c, "数据文件格式异常，请重新上传", err)
	//	return
	//}
	//header = append(header, []string{"Today", "Year", "Month", "Day", "Weekday", "Hour", "Minute", "Second", "-", "_"}...)
	response.Success(c, "文件上传成功", gin.H{"FileName": filename})
}

// @Summary 上传Plain文件
// @Description 上传Plain文件
// @Tags Batch
// @Accept  json
// @Produce  json
// @Security ApiKeyAuth
// @Success 200 {object} model.SysBatch "{"code":0,"msg":"OK","body": {}}"
// @Router /api/v1/batch [post]
func (b BatchController) UploadPlain(c *gin.Context) {
	claims, _ := c.Get("user")
	user := claims.(model.SysUser)
	project := c.DefaultQuery("project", "project")
	file, err := c.FormFile("file")
	if err != nil {
		response.Error(c, "服务器接收文件出错", err)
		return
	}
	dir := fmt.Sprintf("./upload/%s/%s", user.Name, project)
	if err := util.CreateDir(dir); err != nil {
		response.Error(c, "Create DIR faild", err)
		return
	}
	dst := fmt.Sprintf("%s/%s", dir, file.Filename)
	if err := c.SaveUploadedFile(file, dst); err != nil {
		response.Error(c, "服务器处理文件出错", err)
		return
	}
	var batch = UsrBatch{
		Source: fmt.Sprintf("%s/%s.xlsx", dir, project),
		Template: dst,
		Project: project,
	}
	// TODO 读取Excel数据
	data, err := ReadData(batch)
	if err != nil {
		response.Error(c, "读取数据文件出错", err)
		return
	}

	// TODO 渲染文件
	if err:=Render(batch, data);err!=nil{
		response.Error(c, "渲染模板文件出错", err)
		return
	}

	// TODO 渲染完成，将文件夹压缩
	if err = util.Zip(dir + "/", dir+".zip");err !=nil{
		response.Error(c, "压缩文件出错", err)
		return
	}

	response.Success(c, "文件上传成功", dst)
}

// @Summary 执行批量处理任务
// @Description 执行批量处理任务
// @Tags Batch
// @Accept  json
// @Produce  json
// @Security ApiKeyAuth
// @Success 200 {object} model.SysBatch "{"code":0,"msg":"OK","body": {}}"
// @Router /api/v1/batch [post]
func (b BatchController) ExecuteBatch(c *gin.Context) {
	var batch = UsrBatch{}
	if err := c.ShouldBindJSON(&batch); err != nil {
		response.Error(c, "绑定错误", err)
		return
	}
	dir := "./upload/" + batch.Project + "/" + batch.Project
	// TODO 读取Excel数据
	data, err := ReadData(batch)
	if err != nil {
		response.Error(c, "读取数据文件出错", err)
		return
	}

	// TODO 渲染文件
	if err:=Render(batch, data);err!=nil{
		response.Error(c, "渲染模板文件出错", err)
		return
	}

	// TODO 渲染完成，将文件夹压缩
	if err = util.Zip(dir + "/", dir+".zip");err !=nil{
		response.Error(c, "压缩文件出错", err)
		return
	}

	response.Success(c, "执行成功", data)

}

// @Summary 执行批量处理任务
// @Description 执行批量处理任务
// @Tags Batch
// @Accept  json
// @Produce  json
// @Security ApiKeyAuth
// @Success 200 {object} model.SysBatch "{"code":0,"msg":"OK","body": {}}"
// @Router /api/v1/batch [post]
func (b BatchController) DownloadBatch(c *gin.Context) {
	claims, _ := c.Get("user")
	user := claims.(model.SysUser)
	var project = c.DefaultQuery("project", "project")
	dir := fmt.Sprintf("./upload/%s", user.Name)
	filename := fmt.Sprintf("%s/%s.zip", dir, project)
	c.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=%s", project+".zip"))
	c.File(filename)

	////	TODO 删除文件
	//if err:=os.Remove(filename);err!=nil{
	//	log.Error("删除文件失败， ", err)
	//}

	//	TODO 删除文件夹 dir就是 ./upload/{user.Name}
	if err:=os.RemoveAll(dir);err!=nil{
		log.Error("删除文件夹失败， ", err)
	}
}


func NewBatchController() *BatchController {
	return &BatchController{}
}

func ReadHeader(filename string) ([]string, error) {
	f, err := excelize.OpenFile(filename)
	if err != nil {
		return nil, err
	}
	rows, err := f.GetRows(f.GetSheetName(0))
	if err != nil {
		return nil, err
	}
	return rows[0], nil
}

func ReadData(batch UsrBatch)([]map[string]interface{}, error ){
	f, err := excelize.OpenFile(batch.Source)
	if err != nil {
		//response.Error(c, "打开Excel错误", err)
		return nil, err
	}
	//defer f.Close()
	rows, err := f.GetRows(f.GetSheetName(0))
	if err != nil {
		//response.Error(c, "读取Excel错误", err)
		return nil, err
	}
	// TODO 生成当前时间
	now := time.Now()

	var data []map[string]interface{}
	data = make([]map[string]interface{}, len(rows)-1)
	header := rows[0]
	for i, row := range rows[1:] {
		temp := make(map[string]interface{})
		temp["Year"], temp["Month"], temp["Day"] = now.Date()
		temp["Hour"], temp["Minute"], temp["Second"] = now.Clock()
		temp["Weekday"] = now.Weekday()
		temp["Today"] = now.Format("2006-01-02")
		temp["Time"] = now.Format("15:04:05")  // 文件名不能有冒号
		temp["Now"] = now.Format("2006-01-02 15:04:05") // 文件名不能有冒号
		for j, cell := range row {
			temp[header[j]] = cell
		}
		data[i] = temp
	}
	return data, nil
}

func Render(batch UsrBatch, data []map[string]interface{}) error{
	tmplfile, err := template.ParseFiles(batch.Template)
	if err != nil {
		//response.Error(c, "读取模板错误", err)
		return err
	}
	tmplname, err := template.New("FN").Parse(batch.Template)
	if err != nil {
		//response.Error(c, "读取文件名规则错误", err)
		return err
	}
	dir := "./upload/" + "batch/" + batch.Project + "/"
	for _, row := range data {

		if err := util.CreateDir(dir); err != nil {
			//response.Error(c, "Create DIR faild", err)
			return err
		}
		//ext := path.Ext(batch.Template)
		var filename bytes.Buffer
		if err = tmplname.Execute(&filename, row);err!=nil{
			//response.Error(c, "Format FILENAME faild", err)
			return err
		}
		f, err := os.Create(filename.String())
		if err != nil {
			//response.Error(c, "Create FILE faild", err)
			return err
		}
		defer func() {
			if err = f.Close(); err!= nil{
				panic("Close File Faild")
			}
		}()

		err = tmplfile.Execute(f, row)
		if err != nil {
			//response.Error(c, "渲染模板出错", err)
			return err
		}
	}
	return nil
}